/**
 * Copyright 2014-2020  the original author or authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.upb.webserver.account.developer;

import cn.hutool.core.collection.CollectionUtil;
import com.upb.webserver.account.AccountService;
import com.upb.webserver.application.ApplicationManager;
import com.upb.webserver.application.ApplicationService;
import com.upb.webserver.chain.ChainManager;
import com.upb.webserver.common.constant.MessageConstant;
import com.upb.webserver.common.enums.AccountStatusEnum;
import com.upb.webserver.common.enums.PlatformEnum;
import com.upb.webserver.common.enums.RegexPattern;
import com.upb.webserver.common.enums.RoleTypeEnum;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.pojo.account.developer.ReqAddDeveloperVO;
import com.upb.webserver.common.pojo.account.developer.ReqDeveloperRegisterVO;
import com.upb.webserver.common.pojo.account.developer.ReqModifyDeveloperVO;
import com.upb.webserver.common.pojo.account.developer.RspDeveloperVO;
import com.upb.webserver.common.pojo.base.BasePageResponse;
import com.upb.webserver.common.properties.WebServerProperties;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.common.tools.MybatisExampleTools;
import com.upb.webserver.common.tools.WebServerTools;
import com.upb.webserver.company.CompanyDeveloperManager;
import com.upb.webserver.company.CompanyDeveloperService;
import com.upb.webserver.company.CompanyService;
import com.upb.webserver.dao.entity.*;
import com.upb.webserver.dao.mapper.*;
import com.upb.webserver.developerappmap.DeveloperAppMapService;
import com.upb.webserver.host.HostManager;
import com.upb.webserver.message.MessageService;
import com.upb.webserver.order.WorkOrderManager;
import com.upb.webserver.org.OrgManager;
import com.upb.webserver.token.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * services for account data.
 */
@Slf4j
@Service
public class DeveloperService {

    @Autowired
    private TbCompanyMapper companyMapper;
    @Autowired
    private TbDeveloperMapper developerMapper;
    @Autowired
    private CompanyService companyService;
    @Qualifier(value = "bCryptPasswordEncoder")
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private CompanyDeveloperService companyDeveloperService;
    @Autowired
    private DeveloperAppMapService developerAppMapService;
    @Autowired
    private ApplicationService applicationService;
    @Autowired
    private ApplicationManager applicationManager;
    @Autowired
    private TbRoleMapper roleMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private TbCompanyDeveloperMapper tbCompanyDeveloperMapper;
    @Autowired
    private AccountService accountService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private WebServerProperties webServerProperties;
    @Autowired
    private HostManager hostManager;
    @Autowired
    private OrgManager orgManager;
    @Autowired
    private ChainManager chainManager;
    @Autowired
    private WorkOrderManager orderManager;
    @Autowired
    private TbSecurityMapper securityMapper;
    @Autowired
    private CompanyDeveloperManager companyDeveloperManager;

    /**
     * register.
     */
    @Transactional
    public RspDeveloperVO register(ReqDeveloperRegisterVO param) throws WebServerException {
        log.info("start exec method [register]. param:{}", JsonUtils.objToString(param));

        //save developer
        TbDeveloper tbDeveloper = new TbDeveloper();
        BeanUtils.copyProperties(param, tbDeveloper);
        tbDeveloper.setRoleId(roleMapper.selectRoleIdByRoleName(RoleTypeEnum.DEVELOPER_MASTER.getName()));
        tbDeveloper.setCreateFromPlatform(PlatformEnum.DEVELOPER.getId());
        tbDeveloper.setStatus(AccountStatusEnum.FREEZE.getId());
        TbDeveloper developerRecord = ((DeveloperService) AopContext.currentProxy()).newDeveloper(tbDeveloper);

        //save company
        Integer companyRecordId = companyService.newCompany(developerRecord.getId(), param.getCompanyName());

        //save company-developer
        companyDeveloperService.newCompanyDeveloper(companyRecordId, developerRecord.getId(), PlatformEnum.DEVELOPER.getId(), developerRecord.getId());

        // send email or mobile message
        messageService.addInfoMessage(PlatformEnum.DEVELOPER.getId(), Arrays.asList(developerRecord.getId()), MessageConstant.INFO_REGISTER_SUCCESS);

        log.info("success exec method [register]");
        return  queryDeveloperDetail(developerRecord.getId());
    }


    @Transactional
    public RspDeveloperVO addByOtherAccount(Byte fromPlatform, Integer currentAccountId, ReqAddDeveloperVO param) {
        log.info("start exec method [add] . fromPlatform:{} currentAccountId:{} param:{}", fromPlatform, currentAccountId, JsonUtils.objToString(param));

        //add
        TbDeveloper tbDeveloper = new TbDeveloper();
        BeanUtils.copyProperties(param, tbDeveloper);
        tbDeveloper.setCreateFromPlatform(fromPlatform);
        tbDeveloper.setRoleId(roleMapper.selectRoleIdByRoleName(RoleTypeEnum.DEVELOPER_GENERAL.getName()));
        TbDeveloper developerRecord = ((DeveloperService) AopContext.currentProxy()).newDeveloper(tbDeveloper);

        //update
        Integer companyId;
        if (PlatformEnum.DEVELOPER.getId() == fromPlatform) {
            //add developer-app map
            companyId = companyDeveloperService.selectCompanyIdByDeveloperId(currentAccountId);
            developerAppMapService.addByDeveloperSetAndCompanySet(CollectionUtil.newHashSet(developerRecord.getId()), CollectionUtil.newHashSet(companyId));
        } else if (Arrays.asList(PlatformEnum.DEV_OPS.getId()).contains(fromPlatform)) {

            companyId = companyService.queryIdByName(param.getCompanyName());
            if (null == companyId) {
                companyId = companyService.newCompany(developerRecord.getId(), param.getCompanyName());
                tbDeveloper.setRoleId(roleMapper.selectRoleIdByRoleName(RoleTypeEnum.DEVELOPER_MASTER.getName()));
                developerMapper.updateByPrimaryKey(developerRecord);
            } else {
                companyDeveloperManager.requireCompanyFoundByPlatformAndManager(companyId, fromPlatform, currentAccountId);
            }


        } else {
            log.warn("fail exec method[add]. not support fromPlatform:{}", fromPlatform);
            throw new WebServerException(ConstantCode.PLATFORM_NOT_SUPPORT);
        }

        //save company-developer
        companyDeveloperService.newCompanyDeveloper(companyId, developerRecord.getId(), fromPlatform, currentAccountId);

        return  queryDeveloperDetail(developerRecord.getId());
    }


    /**
     * @param developerId
     * @return
     */
    public RspDeveloperVO queryDeveloperDetail(int developerId) {
        log.info("start exec method [queryDeveloperDetail]. developerId:{}", developerId);
        //developer
        //TbDeveloper tbDeveloper = developerMapper.selectByPrimaryKey(developerId);
        TbDeveloperWithAppID tbDeveloper = developerMapper.selectByPrimaryKeyWithAppId(developerId);
        //company
        int companyId = companyDeveloperService.selectCompanyIdByDeveloperId(developerId);
        TbCompany tbCompany = companyMapper.selectByPrimaryKey(companyId);
        //result
        RspDeveloperVO obj = new RspDeveloperVO();
        BeanUtils.copyProperties(tbDeveloper, obj);
        obj.setCompanyName(tbCompany.getCompanyName());
        log.info("success exec method [queryDeveloperDetail]. result:{}", JsonUtils.objToString(obj));
        return obj;
    }


    /**
     * @param companyDeveloperId
     */
    @Transactional
    public void deleteContactPerson(int companyDeveloperId) {
        log.info("start exec method [deleteContactPerson].companyDeveloperId:{}", companyDeveloperId);
        TbCompanyDeveloper companyDeveloper = tbCompanyDeveloperMapper.selectByPrimaryKey(companyDeveloperId);
        if (Objects.isNull(companyDeveloper)) {
            log.warn("fail exec method [deleteContactPerson]. not found record by companyDeveloperId:{}", companyDeveloperId);
            throw new WebServerException(ConstantCode.INVALID_CONTACT_PERSON_ID);
        }

        int developerId = 0;
        if ((developerId = companyDeveloper.getDeveloperId()) == companyDeveloper.getCreateBy()) {
            log.warn("fail exec method [deleteContactPerson]. developerId:{}  is equal to CreateBy,can not be delete", companyDeveloperId);
            throw new WebServerException(ConstantCode.NOT_SUPPORT_OPERATE.msg("not support to delete master account"));
        }

        TbDeveloper developer = verifyDeveloperId(developerId);

        tbCompanyDeveloperMapper.deleteByPrimaryKey(companyDeveloperId);
        developerMapper.deleteByPrimaryKey(developerId);
        securityMapper.deleteByRelatedKey(String.valueOf(PlatformEnum.DEVELOPER.getId()), developer.getAccount());

        if (isDeveloperInUse(developerId)) {
            log.warn("fail exec method [deleteContactPerson].companyDeveloperId:{}. developerId:{} has bean in use", companyDeveloperId, developerId);
            throw new WebServerException(ConstantCode.ACCOUNT_HAS_BEAN_IN_USED);
        }

        log.info("success exec method [deleteContactPerson].companyDeveloperId:{} developerId:{}", companyDeveloperId, developerId);
    }


    /**
     * @param developerId
     * @return
     */
    public boolean isDeveloperInUse(int developerId) {
        log.info("start exec method [isDeveloperInUse]. developerId:{}", developerId);

        if (hostManager.countHostByCreator(PlatformEnum.DEVELOPER, developerId) > 0) {
            log.info("finish exec method [isDeveloperInUse]. found host record by developerId:{}", developerId);
            return true;
        }
        if (orgManager.countOrgByCreator(PlatformEnum.DEVELOPER, developerId) > 0) {
            log.info("finish exec method [isDeveloperInUse]. found org record by developerId:{}", developerId);
            return true;
        }
        if (applicationManager.countApplicationByCreator(PlatformEnum.DEVELOPER, developerId) > 0) {
            log.info("finish exec method [isDeveloperInUse]. found application record by developerId:{}", developerId);
            return true;
        }
        if (chainManager.countChainByCreator(PlatformEnum.DEVELOPER, developerId) > 0) {
            log.info("finish exec method [isDeveloperInUse]. found chain record by developerId:{}", developerId);
            return true;
        }
        if (orderManager.countWorkOrderByCreator(PlatformEnum.DEVELOPER, developerId) > 0) {
            log.info("finish exec method [isDeveloperInUse]. found workOrder record by developerId:{}", developerId);
            return true;
        }

        Set<Integer> workOrderIdSet = orderManager.getAllWorkOrderOfNewApplicationByDeveloperId(developerId);
        if (CollectionUtil.isNotEmpty(workOrderIdSet)) {
            log.info("finish exec method [isDeveloperInUse]. found workOrder of new application record by developerId:{}", developerId);
            return true;
        }
        log.info("finish exec method [isDeveloperInUse]. developerId:{} is not in use", developerId);
        return false;
    }

    /**
     * @param param
     * @param currentAccountId
     */
    public void modifyDeveloper(ReqModifyDeveloperVO param, int currentAccountId) {

        TbDeveloper tbDeveloper = developerMapper.selectByMobile(param.getMobile());
        if (Objects.nonNull(tbDeveloper) && tbDeveloper.getId().intValue() != currentAccountId) {
            log.warn("found record by mobile:{}", param.getMobile());
            throw new WebServerException(ConstantCode.MOBILE_HAS_BEAN_IN_USED);
        }
        tbDeveloper = developerMapper.selectByEmail(param.getEmail());
        if (Objects.nonNull(tbDeveloper) && tbDeveloper.getId().intValue() != currentAccountId) {
            log.warn("found record by email:{}", param.getEmail());
            throw new WebServerException(ConstantCode.EMAIL_HAS_BEAN_IN_USED);
        }

        //modify self
        TbDeveloper developer = developerMapper.selectByPrimaryKey(currentAccountId);
        BeanUtils.copyProperties(param, developer);
        developer.setGmtModified(new Date());
        developerMapper.updateByPrimaryKey(developer);

        //modify companyName
        int companyId = companyDeveloperService.selectCompanyIdByDeveloperId(currentAccountId);
        companyService.modifyCompanyName(companyId, param.getCompanyName());

    }


    /**
     * @param developer
     * @return
     */
    @Transactional
    public TbDeveloper newDeveloper(TbDeveloper developer) {
        log.info("start exec method [newDeveloper], developer:{}", JsonUtils.objToString(developer));

        //check param
        this.checkBeforeNewDeveloper(developer.getAccount(), developer.getMobile(), developer.getEmail());
        developer.setPassword(passwordEncoder.encode(developer.getPassword()));
        developer.setGmtCreate(new Date());
        developer.setGmtModified(new Date());


        developerMapper.insertSelective(developer);
        String pid = PlatformEnum.DEVELOPER.getId() + "";
        securityMapper.insertByInfos(pid, developer.getAccount(), UUID.randomUUID().toString(), UUID.randomUUID().toString());

//        //new fisco user
//        if (webServerProperties.getSupportFiscoBcos()) {
//            fiscoChainMgrRestService.newUser(developer.getId());
//        }

        TbDeveloper tbDeveloper = developerMapper.selectByPrimaryKey(developer.getId());
        log.info("success exec method [newDeveloper], return:{}", JsonUtils.objToString(tbDeveloper));
        return tbDeveloper;
    }


    /**
     * @param account
     * @param mobile
     * @param email
     */
    public void checkBeforeNewDeveloper(String account, Long mobile, String email) {
        //regex pattern
//        if (!WebServerTools.matcher(RegexPattern.MOBILE, String.valueOf(mobile))) {
//            log.warn("mobile not match:{}", email);
//            throw new WebServerException(ConstantCode.MOBILE_NOT_MATCH);
//        }



        //check record
        TbDeveloper tbDeveloper = developerMapper.selectByAccount(account);
        if (tbDeveloper != null) {
            log.warn("found record by account:{}", account);
            throw new WebServerException(ConstantCode.ACCOUNT_HAS_BEAN_IN_USED);
        }


        if(StringUtils.isNotBlank(email)){
            if (!WebServerTools.matcher(RegexPattern.EMAIL,email)) {
                log.warn("email not match:{}", email);
                throw new WebServerException(ConstantCode.EMAIL_NOT_MATCH);
            }

            tbDeveloper = developerMapper.selectByEmail(email);
            if (Objects.nonNull(tbDeveloper)) {
                log.warn("found record by email:{}", email);
                throw new WebServerException(ConstantCode.EMAIL_HAS_BEAN_IN_USED);
            }
        }

        if(null != mobile){
            tbDeveloper = developerMapper.selectByMobile(mobile);
            if (Objects.nonNull(tbDeveloper)) {
                log.warn("found record by mobile:{}", mobile);
                throw new WebServerException(ConstantCode.MOBILE_HAS_BEAN_IN_USED);
            }
        }
    }


    /**
     * @param currentPlatform
     * @param currentAccountId
     * @param status
     * @param pageNumber
     * @param pageSize
     * @return
     */
    public BasePageResponse queryByPage(Byte currentPlatform, String currentAccountRole, Integer currentAccountId, Byte status, int pageNumber, int pageSize) {
        log.info("start exec method [queryDeveloperByPage]. currentPlatform:{} currentAccountId:{} pageNumber:{} pageSize:{} status:{}", currentPlatform, currentAccountId, pageNumber, pageSize, status);
        //query param
        if (PlatformEnum.DEVELOPER.getId() == currentPlatform) {
            return queryContactPersonByPage(currentAccountId, status, pageNumber, pageSize);
        }

        if (PlatformEnum.DEV_OPS.getId() == currentPlatform) {
            List<Integer> developerIdList = null;
            if (RoleTypeEnum.API_MANAGER.getName().equalsIgnoreCase(currentAccountRole)) {
                developerIdList = companyDeveloperManager.listDeveloperIdByPlatformAndAccountId(currentPlatform, currentAccountId);
                if (CollectionUtil.isEmpty(developerIdList))
                    return BasePageResponse.initialize();
            }

            return queryAllDeveloperByPage(status, pageNumber, pageSize, developerIdList);
        }

        log.warn("fail exec method[add]. not support currentPlatform:{}", currentPlatform);
        throw new WebServerException(ConstantCode.PLATFORM_NOT_SUPPORT);
    }


    /**
     * @param status
     * @param pageNumber
     * @param pageSize
     * @return
     */
    private BasePageResponse queryAllDeveloperByPage(Byte status, int pageNumber, int pageSize, List<Integer> developerIdList) {
        log.info("start exec method [queryAllDeveloperByPage]. pageNumber:{} pageSize:{} status:{} developerIdList:{}", pageNumber, pageSize, status, JsonUtils.objToString(developerIdList));
        BasePageResponse pageResponse = BasePageResponse.initialize();
        //query param
        TbDeveloperExample example = MybatisExampleTools.initSamplePageExample(TbDeveloperExample.class, pageNumber, pageSize, new TbDeveloper(status));

        if (CollectionUtil.isNotEmpty(developerIdList)) {
            TbDeveloperExample.Criteria criteria = example.createCriteria();
            criteria.andIdIn(developerIdList);
            example.getOredCriteria().add(criteria);
        }

        pageResponse.setTotalCount(developerMapper.countByExample(example));
        if (pageResponse.getTotalCount() > 0) {
            //query
            //List<TbDeveloper> developerList = developerMapper.selectByExample(example);
            List<TbDeveloperWithAppID> developerList = developerMapper.selectWithAppID(example);
            //convert to RspDeveloperVO
            List<RspDeveloperVO> list = new ArrayList<>(developerList.size());
            for (TbDeveloperWithAppID developer : developerList) {
                RspDeveloperVO obj = new RspDeveloperVO();
                BeanUtils.copyProperties(developer, obj);
                obj.setCompanyName(companyDeveloperService.selectCompanyNameByDeveloperId(developer.getId()));
                list.add(obj);
            }
            pageResponse.setData(list);
        }

        log.info("success exec method [queryAllDeveloperByPage]. result:{}", JsonUtils.objToString(pageResponse));
        return pageResponse;
    }

    /**
     * query by page.
     *
     * @param pageNumber
     * @param pageSize
     * @return
     */
    private BasePageResponse queryContactPersonByPage(int currentDeveloper, Byte status, int pageNumber, int pageSize) {
        log.info("start exec method [queryContactPersonByPage]. currentDeveloper:{} pageNumber:{} pageSize:{} status:{}", currentDeveloper, pageNumber, pageSize, status);
        BasePageResponse pageResponse = BasePageResponse.initialize();

        //company id
        TbCompanyDeveloper tbCompanyDeveloper = tbCompanyDeveloperMapper.selectByDeveloper(currentDeveloper);
        //query param
        TbCompanyDeveloperExample example = MybatisExampleTools.initSamplePageExample(TbCompanyDeveloperExample.class, pageNumber, pageSize, new TbCompanyDeveloper(tbCompanyDeveloper.getCompanyId(), status));
        pageResponse.setTotalCount(tbCompanyDeveloperMapper.countByExample(example));
        if (pageResponse.getTotalCount() > 0) {
            //query
            List<TbCompanyDeveloper> tbCompanyDevelopers = tbCompanyDeveloperMapper.selectByExample(example);
            if (tbCompanyDevelopers != null && tbCompanyDevelopers.size() > 0) {
                List<Integer> developerIds = tbCompanyDevelopers.stream().map(m -> m.getDeveloperId()).collect(Collectors.toList());
//                List<TbDeveloper> developerList = developerMapper.listByDeveloperIds(developerIds);

                TbDeveloperExample developerExample = new TbDeveloperExample();
                TbDeveloperExample.Criteria criteria = developerExample.createCriteria();
                criteria.andIdIn(developerIds);

                pageResponse.setTotalCount(developerMapper.countByExample(developerExample));
                List<TbDeveloperWithAppID> developerList = developerMapper.selectWithAppID(developerExample);

                //convert to RspDeveloperVO
                List<RspDeveloperVO> list = new ArrayList<>(tbCompanyDevelopers.size());
                for (TbDeveloperWithAppID developer : developerList) {
                    if (developer.getId() == currentDeveloper) continue;
                    RspDeveloperVO obj = new RspDeveloperVO();
                    BeanUtils.copyProperties(developer, obj);
                    obj.setCompanyDeveloperId(tbCompanyDevelopers.stream().filter(cd -> cd.getDeveloperId() == developer.getId()).map(cd1 -> cd1.getId()).findFirst().get());
                    list.add(obj);
                }
                pageResponse.setData(list);
            }
        }

        log.info("success exec method [queryContactPersonByPage]. result:{}", JsonUtils.objToString(pageResponse));
        return pageResponse;
    }

    /**
     * @param developerId
     */
    public void freeze(int developerId, String description) {
        log.info("start exec method [freeze]. developerId:{} description:{}", developerId, description);
        TbDeveloper developer = developerMapper.selectByPrimaryKey(developerId);
        if (Objects.isNull(developer)) {
            log.warn("start exec method [freeze]. not found record by id:{}", developerId);
            throw new WebServerException(ConstantCode.INVALID_DEVELOPER_ID);
        }
        developer.setStatus(AccountStatusEnum.FREEZE.getId());
        developer.setDescription(description);
        developerMapper.updateByPrimaryKeyWithBLOBs(developer);
    }

    /**
     * @param developerId
     */
    public void unfreeze(int developerId, String description) {
        log.info("start exec method [freeze]. developerId:{} description:{}", developerId, description);
        TbDeveloper developer = developerMapper.selectByPrimaryKey(developerId);
        if (Objects.isNull(developer)) {
            log.warn("start exec method [freeze]. not found record by id:{}", developerId);
            throw new WebServerException(ConstantCode.INVALID_DEVELOPER_ID);
        }
        developer.setStatus(AccountStatusEnum.NORMAL.getId());
        developer.setDescription(description);
        developerMapper.updateByPrimaryKeyWithBLOBs(developer);
    }


    /**
     * @param currentAccountId
     * @param oldAccountPwd
     * @param newAccountPwd
     */
    public void updatePassword(int currentAccountId, String oldAccountPwd, String newAccountPwd) {
        log.debug("start updatePassword. currentAccountId:{} oldAccountPwd:{} newAccountPwd:{}",
                currentAccountId, oldAccountPwd, newAccountPwd);

        // query target account info
        TbDeveloper targetRow = developerMapper.selectByPrimaryKey(currentAccountId);

        if (StringUtils.equals(oldAccountPwd, newAccountPwd)) {
            log.warn("fail updatePassword. the new password cannot be same as old ");
            throw new WebServerException(ConstantCode.NEW_PWD_EQUALS_OLD);
        }

        // check old password
        if (!passwordEncoder.matches(oldAccountPwd, targetRow.getPassword())) {
            throw new WebServerException(ConstantCode.PASSWORD_ERROR);
        }

        // update password
        targetRow.setPassword(passwordEncoder.encode(newAccountPwd));
        targetRow.setStatus(AccountStatusEnum.NORMAL.getId());
        Integer affectRow = developerMapper.updateByPrimaryKey(targetRow);

        log.debug("end updatePassword. affectRow:{}", affectRow);

    }


    /**
     * @param developerId
     * @return
     */
    public TbDeveloper verifyDeveloperId(int developerId) {
        log.info("start exec method [verifyDeveloperId]. developerId:{}", developerId);
        TbDeveloper tbDeveloper = developerMapper.selectByPrimaryKey(developerId);
        if (Objects.isNull(tbDeveloper)) {
            log.warn("fail exec method [verifyDeveloperId]. not found record by developerId{}", developerId);
            throw new WebServerException(ConstantCode.INVALID_DEVELOPER_ID);
        }
        log.info("success exec method [verifyDeveloperId]. result:{}", JsonUtils.objToString(tbDeveloper));
        return tbDeveloper;
    }

    //TODO wait for work order
    public void proof(int workerId) {
    }
}
